<?php
/*
Plugin Name: vbWorldEevent
Plugin URI: http://URI_Of_Page_Describing_Plugin_and_Updates
Description: This plugin reads events out of a vbulletin event table and shows
            them in a list. It uses Google to compute the distance between the
            user and the even location
Version: 0.0.1
Author: Lukas Smith
Author URI: http://pooteeweet.org
*/

if (!class_exists('Cache')) {
    require_once 'Cache.php';
}
if (!class_exists('Net_GeoIP')) {
    require_once 'Net/GeoIP.php';
}

if (function_exists('add_action')) {
    add_action('wp_head', 'vbWorldEvent_js_header' );
}

function vbworldevent_get_list($ajax = false)
{
    $dir = dirname(__FILE__);
    require $dir.'/config.php';

    $cache = new Cache('file', array('cache_dir' => $dir.'/geocodecache/'), 3600);

    try {
        $dbh = new PDO($dsn, $user, $password);
    } catch (PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();
    }

    $visitor = false;
    $location = '';
    if (isset($_REQUEST['location'])) {
        $location = $_REQUEST['location'];
    }

    if (empty($location)) {
        $ip = vbworldevent_i2c_realip();
        if ($_SERVER['SERVER_NAME'] == 'localhost') {
            $ip = gethostbyname('www.berlin.de');
        }
        try {
            $geoip = Net_GeoIP::getInstance($dir.'/GeoLiteCity.dat');
            $visitor = $geoip->lookupLocation($ip);
            if ($visitor) {
                $visitor = (array)$visitor;
            }
            $visitor['address'] = $visitor['city'];
        } catch (Exception $e) { }
    } else {
        $visitor = vbworldevent_google_geo($location, $appid, $cache);
    }

    $sql = 'SELECT * FROM event WHERE dateline_from BETWEEN ? AND ? ORDER BY dateline_from';
    $params = array($_SERVER['REQUEST_TIME'], ($_SERVER['REQUEST_TIME']+(60*60*24*$days)));

    $stmt = $dbh->prepare($sql);
    $stmt->execute($params);
    $events = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($events as $key => $event) {
        $optionalinfos = @unserialize($event['customfields']);
        if (!empty($optionalinfos[1])) {
            $event['distance'] = false;
            if (substr($optionalinfos[1], 0, 4) === 'http') {
                $event['location']['url'] = $optionalinfos[1];
                $event['distance'] = 'Web';
            } elseif ($visitor) {
                if (empty($event['location'])) {
                    $event['location'] = vbworldevent_google_geo($optionalinfos[1], $appid, $cache);
                }
                if ($event['location']) {
                    $event['distance'] = vbworldevent_dist($visitor['latitude'], $visitor['longitude'], $event['location']['latitude'], $event['location']['longitude']);
                    $event['distance'].= ' km';
                }
            }

            $event['summary'] = '';
            if (!empty($optionalinfos[2])) {
                $event['summary'] = $optionalinfos[2];
            }

            if ($event['distance']) {
                foreach ($distance_ranges as $range => $list) {
                    if (isset($event['location']['url']) || $range >= (int)$event['distance']) {
                        $distance_ranges[$range][] = $key;
                        $events[$key] = $event;
                        continue 2;
                    }
                }
            }
        }
        unset($events[$key]);
    }

    $results = array();
    if (count($events) <= $display_count) {
        $results = $events;
    } else {
        $count = $display_count;
        foreach ($events as $key => $event) {
            foreach ($distance_ranges as $range => $list) {
                if (in_array($key, $list)) {
                    $results[] = $event;
                    $count--;
                    if ($count == 0) {
                        break 2;
                    }
                }
            }
        }
    }

    ob_start();
    include 'template.php';
    return ob_get_clean();
}

function vbworldvent_translate_specialchars($string)
{
    return iconv("UTF-8", "ISO-8859-1", $string);
}

function vbworldevent_google_geo($location, $appid, $cache)
{
    $id = $cache->generateID($location);
    $ret = $cache->get($id);
    if ($ret) {
        $ret = @unserialize($ret);
    } else {
        $url = 'http://maps.google.com/maps/geo?output=xml&oe=utf8&sensor=true_or_false';
        $url .= '&key='.$appid.'&q='.rawurlencode($location);
        $xml = simplexml_load_file($url);
        if (!$xml && isset($xml->Response->Placemark)) {
            return false;
        }
        $address = (string)$xml->Response->Placemark->address;
        $countryName = (string)$xml->Response->Placemark->AddressDetails->Country->CountryName;
        $city = (string)$xml->Response->Placemark->AddressDetails->Country->AdministrativeArea->AdministrativeAreaName;
        if (isset($xml->Response->Placemark->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->SubAdministrativeAreaName)) {
            $city = (string)$xml->Response->Placemark->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->SubAdministrativeAreaName;
        }
        $accuracy = (string)$xml->Response->Placemark->AddressDetails['Accuracy'];
        $ret = explode(',', $xml->Response->Placemark->Point->coordinates);
        $ret = array(
            'accuracy' => $accuracy,
            'address' => vbworldvent_translate_specialchars($address),
            'countryName' => vbworldvent_translate_specialchars($countryName),
            'city' => vbworldvent_translate_specialchars($city),
            'latitude' => $ret[1],
            'longitude' => $ret[0]
        );
        $cache->save($id, serialize($ret));
    }
    return $ret;
}

// Great Circle Distance
function vbworldevent_dist($lat1, $lon1, $lat2, $lon2)
{
    $pi = 3.1415926;
    $rad = doubleval($pi/180.0);

    $lon1 = doubleval($lon1)*$rad; $lat1 = doubleval($lat1)*$rad;
    $lon2 = doubleval($lon2)*$rad; $lat2 = doubleval($lat2)*$rad;

    $theta = $lon2 - $lon1;
    $dist = acos(sin($lat1) * sin($lat2) + cos($lat1) * cos($lat2) * cos($theta));
    if ($dist < 0) {
        $dist += $pi;
    }
    return round($dist * 6371.2);
}

function vbworldevent_i2c_realip()
{
    // No IP found (will be overwritten by for
    // if any IP is found behind a firewall)
    $ip = false;

    // If HTTP_CLIENT_IP is set, then give it priority
    if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    }

    // User is behind a proxy and check that we discard RFC1918 IP addresses
    // if they are behind a proxy then only figure out which IP belongs to the
    // user.  Might not need any more hackin if there is a squid reverse proxy
    // infront of apache.
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {

        // Put the IP's into an array which we shall work with shortly.
        $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
        if ($ip) {
            array_unshift($ips, $ip);
            $ip = false;
        }

        for ($i = 0; $i < count($ips); $i++) {
            // Skip RFC 1918 IP's 10.0.0.0/8, 172.16.0.0/12 and
            // 192.168.0.0/16
            if (!preg_match('/^(?:10|172\.(?:1[6-9]|2\d|3[01])|192\.168)\./', $ips[$i])) {
                if (version_compare(phpversion(), "5.0.0", ">=")) {
                    if (ip2long($ips[$i]) != false) {
                        $ip = $ips[$i];
                        break;
                    }
                } elseif (ip2long($ips[$i]) != -1) {
                    $ip = $ips[$i];
                    break;
                }
                }
        }
    }

    // Return with the found IP or the remote address
    return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
}

function vbWorldEvent_js_header()
{
  // use JavaScript SACK library for Ajax
  wp_print_scripts( array( 'sack' ));

  // Define custom JavaScript function
?>
<script type="text/javascript">
//<![CDATA[
function vbWorldEvent_update_events(location, events_div)
{
    var mysack = new sack("<?php bloginfo('wpurl'); ?>/wp-content/plugins/vbWorldEvent/vbWorldEvent_ajax.php");

    mysack.execute = 1;
    mysack.method = 'POST';
    mysack.setVar( "location", location.value );
    mysack.setVar( "events_div_id", events_div );
    mysack.onError = function() { alert('Ajax error in event update' )};
    mysack.runAJAX();

    return true;
}
//]]>
</script>
<?php
}
